/*
 * Copyright 2008 CSC Consulting Group under the Apache License, 
 * Version 2.0 (the "License"); you may not use this file except in 
 * compliance with the License. You may obtain a copy of the License at 
 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable 
 * law or agreed to in writing, software distributed under the License is 
 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
 * either express or implied. See the License for the specific language 
 * governing permissions and limitations under the License.
 */
package com.waw.memberMap.plugin;

import com.jivesoftware.base.*;
import com.jivesoftware.community.*;
import com.jivesoftware.base.UserManager;
import com.jivesoftware.community.ProfileField.Type;
import com.jivesoftware.community.lifecycle.JiveApplication;
import com.jivesoftware.base.AuthFactory;

import java.util.*;

/**
 * PluginUtils provides a set of utility functions for the plugin.  
 * These include:
 * <ul>
 * <li>Manager retrieval functions; e.g., getCommunityManager()
 * <li>Community membership functions; e.g., hasMembers(Community), getAllMembers(Community)
 * </ul>
 * The community membership functions assume an underlying naming convention that groups associated
 * with a community start with the community's display name.  For example, the groups <em>newyork.leaders</em> and
 * <em>newyork.members</em> are associated with the community <em>newyork</em>.
 * <p>
 * The groups may be employed to provide the group members with particular capabilities with respect to the community.
 * 
 * @see com.waw.memberMap.plugin.PortalUser
 * 
 * @author Jim Tremlett
 */
public class PluginUtils {

   /**
   * Gets the community manager with system permissions.
   * 
   * @return The community manager.
   */  
   public static CommunityManager getCommunityManager()
   {	  
	  CommunityManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getCommunityManager(); 
	  return manager;	   
   }

   /**
    * Gets the user manager with system permissions.
    * 
    * @return The user manager.
    */     
   public static UserManager getUserManager()
   {	  
	  UserManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getUserManager(); 
	  return manager;	   
   }  

   /**
    * Gets the presence manager with system permissions.
    * 
    * @return The presence manager.
    */   
   public static PresenceManager getPresenceManager()
   {	  
	  PresenceManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getPresenceManager(); 
	  return manager;	   
   }  
   
   /**
    * Gets the group  manager with system permissions.
    * 
    * @return The group manager.
    */   
   public static GroupManager getGroupManager()
   {	  
	  GroupManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getGroupManager(); 
	  return manager;	   
   } 

   /**
    * Gets the profile  manager with system permissions.
    * 
    * @return The profile   manager.
    */ 
   public static ProfileManager getProfileManager()
   {
		  ProfileManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getProfileManager(); 
		  return manager;	 
   }
   
   /**
    * Gets the profile field  manager with system permissions.
    * 
    * @return The profile field manager.
    */ 
   public static ProfileFieldManager getProfileFieldManager()
   {
		  ProfileFieldManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getProfileFieldManager(); 
		  return manager;	 
   }
   
   /**
    * Gets the avatar  manager with system permissions.
    * 
    * @return The avatar manager.
    */ 
   public static AvatarManager getAvatarManager()
   {
		  AvatarManager manager = JiveApplication.getContext(AuthFactory.getSystemAuthToken()).getAvatarManager(); 
		  return manager;	 
   }
   
   /**
    * This method indicates if the specified community has members.
 * @param community the community to check
 * @return <em>true</em> if the community has members; <em>false</em> otherwise.
 */
public static boolean hasMembers(Community community)
   {
	   return getAllMembers(community).size() > 0;
   }
   
   /**
    * Indicates if the specified community has groups defined.
 * @param community the community to check
 * @return <em>true</em> if the community has groups defined; <em>false</em> otherwise.
 */
public static boolean hasGroups(Community community)
   {
	   String commName = community.getDisplayName();
	   
	   // check if there are groups with the same starting name as the community
	   Iterator<Group> groups = getGroupManager().getGroups().iterator();
	   while(groups.hasNext())
	   {
		   Group group = groups.next();
		   if(group.getName().startsWith(commName)) return true;
	   }	   
	   return false;
   }
   

   /**
    * Returns the list of members associated with the community.  This list is composed of the members of all
    * groups associated with the community; i.e., that have a name that begins with the community's displayName.
 * @param community the community to check for members
 * @return a List of the members.  The list is empty if there are no groups or members associated with the community.
 */
public static List<PortalUser> getAllMembers(Community community)
   {
	  ArrayList<PortalUser> list = new ArrayList<PortalUser>();
	  Set<User> userSet = new HashSet<User>();
	   String commName = community.getDisplayName();
	   
	   Log.debug("Getting members for "+commName);
	   
	   // get the groups with the same starting name as the community
	   Iterator<Group> groups = getGroupManager().getGroups().iterator();
	   while(groups.hasNext())
	   {
		   Group group = groups.next();
		   if(group.getName().startsWith(commName))
		   {
			   Log.debug("Retrieving members from "+group.getName());
			   Iterator<User> users = group.getMembers().iterator();

			   while(users.hasNext())			   
			   {
				   User thisUser = users.next();
				   //If user is already part of the set, don't add it again.
				   if(!userSet.contains(thisUser))
				   {
					   userSet.add(thisUser);
					   PortalUser pUser = createAndSetPortalUser(thisUser);				   
					   list.add(pUser);
				   }
			   }
		   }
	   }	   
	   return list;
   }

/**
 * This method encapsulates the logic that translates between a User and a PortalUser.
 * The data copied from the User to the PortalUser is:
 * <ul>
 *  <li>The user name, userName, and email address
 *  <li>The user's profile data
 *  <li>The user's avatar ID
 *  <li>The user's longitude and latitude 
 * </ul>
 * @param user the User to use when creating a PortalUser
 * @return A PortalUser for the specified User
 */
private static PortalUser createAndSetPortalUser(User user)
{	
	 PortalUser pUser = new PortalUser();
	 
	 // set the displayed profile fields into the user
	 pUser.setProfile(getProfile(user));
	 
	 // Set the values from the User
	 pUser.setName(user.getName());
	 pUser.setUsername(user.getUsername());
	 pUser.setEmail(user.getEmail());
	 
	 //Set whether to display the user
	 String displayFieldID = JiveGlobals.getJiveProperty(MemberMapConsts.GLOBAL_MMAP_DISPLAY).trim();
	 Log.debug("Display Field: "+displayFieldID);
	 Map<Long,UserProfile> map = PluginUtils.getProfileManager().getProfile(user);
	 if(displayFieldID != null)
	 {
		Long dispID = new Long(displayFieldID);
		UserProfile displayProfile = map.get(dispID);
		String dispValue;
		if(displayProfile != null) dispValue = displayProfile.getValue().trim().toLowerCase();
		else dispValue = "";
		pUser.setDisplay(dispValue);
	 }
	 else pUser.setDisplay("");
	 
	 //Set the avatar ID
	 String id = Long.toString(getAvatarManager().getActiveAvatar(user).getID());
	pUser.setAvatarID(id);
	
	//  set the user's latitude and longitude
	Map<String, String> properties = user.getProperties();
	String lat = properties.get(MemberMapConsts.USER_MMAP_LAT);
	String lng = properties.get(MemberMapConsts.USER_MMAP_LON);
	
	if(lat != null && lng != null)
	{
		pUser.setLat(lat);
		pUser.setLng(lng);
	}
	else Log.info("No geocode location set for "+user.getName());

	return pUser;
	}

	/**
	 * Creates a Properties object that contains the user's profile fields that should be displayed in the InfoWindow.
	 * The key of each property element is the name of the profile field, the value is the value of the profile field.
	 * @param user the user to retrieve the profile
	 * @return a Java Properties object with the profile values
	 */
	public static Iterator<PortalProfileField> getProfile(User user)
	{
		 Iterator<ProfileField> fieldIter = getProfileFieldManager().getProfileFields().iterator();
		 Map<Long,UserProfile> userProfile = getProfileManager().getProfile(user);
		 ArrayList<Long> displayedFields = getDisplayedFields();
		 ArrayList<PortalProfileField> retArray = new ArrayList<PortalProfileField>();
		 
		 // copy the user profile to the Portal User
		 while(fieldIter.hasNext())
		 {
			 ProfileField field = fieldIter.next();
			 if(displayedFields.contains(new Long(field.getID())))
			 {
				 Type type = field.getType();
				 String key = field.getName();
				 UserProfile up = userProfile.get(field.getID());
				 String output = "";
				 if(up != null)
				 {
					 if(type == ProfileField.Type.URL)
					 {
						 String url = type.getFormatter().format(up.getValue(), user);
						 output = "<a href='"+url+"'>"+url+"</a>";
					 }
					 else output = type.getFormatter().format(up.getValue(), user);	
					 if(output == null)output="";
					 retArray.add(new PortalProfileField(key,output));
					 }
				 else retArray.add(new PortalProfileField(key,""));
			 }
		 }
		 return retArray.iterator();
	}

	/**
	 * Returns the fields displayed in the InfoWindows on Google Maps
	 * @return an ArrayList of ID for the profile fields displayed.
	 */
	public static ArrayList<Long> getDisplayedFields() 
	{
		String displayedFields = JiveGlobals.getJiveProperty(MemberMapConsts.GLOBAL_MMAP_INFO, "");
		StringTokenizer st = new StringTokenizer(displayedFields,",");
		ArrayList<Long> rv = new ArrayList<Long>();
		while(st.hasMoreElements())
		{
			String field = st.nextToken().trim();
			Log.debug("Info Field: "+field);
			rv.add(new Long(field));
		}
		return rv;
	}

	/**
	 * Returns the communities that are children of a parent community
	 * @param community the parent community
	 * @return A list of the children communities.
	 */
	public static ArrayList<Community> getListOfCommunities(Community community) {
		ArrayList<Community> commList = new ArrayList<Community>();
		commList.add(community);
		JiveIterator<Community> communities = community.getCommunities();
		while(communities.hasNext())
		{
			Community child = communities.next();
			ArrayList<Community> childComms = PluginUtils.getListOfCommunities(child);
			commList.addAll(childComms);
		}
		return commList;
	}
}